/*
 *      proc_list.cpp
 *
 *      Copyright 2009 AzureSky <AzureSky.fedora@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#include "proc_list.h"

proc_list::proc_list()
{
}

proc_list::~proc_list()
{
}

void proc_list::read_proc()
{
	DIR* dir;
	struct dirent* ptr;
	dir = opendir("/proc");
	while((ptr = readdir(dir)) != NULL){
		if(is_pid(ptr -> d_name)){
			add_proc(ptr -> d_name);
		}
	}
	closedir(dir);
}

void proc_list::refresh()
{
	clear();
	read_proc();
}

bool proc_list::is_pid(char name[])
{
	int i;
	for(i = 0;name[i] != '\0';i++){
		if(!isdigit(name[i]))
			return false;
	}
	return true;
}

unsigned long long proc_list::get_uptime()
{
	double uptime[2];
	int name_fd;
	char uptime_buff[512];
	
	name_fd = open("/proc/uptime",O_RDONLY);
	read(name_fd,uptime_buff,sizeof(uptime_buff));
	close(name_fd);
	std::istringstream str(uptime_buff);
	str >> uptime[0];
	str >> uptime[1];
	return uptime[0]*100;
}

int proc_list::get_proc_uid(char name[])
{
	int name_fd;
	int uid[4] ;
	char proc_buff[512];
	char file_path[128];
	std::string temp_sscanf;
	
	sprintf(file_path,"/proc/%s/status",name);
	name_fd = open(file_path,O_RDONLY);
	read(name_fd,proc_buff,sizeof(proc_buff));
	close(name_fd);
	
	memset(uid,'\0',sizeof(uid));
	std::string uid_buff(proc_buff);
	unsigned int temp_uid = uid_buff.find("Uid:",0);
	unsigned int temp = uid_buff.find_first_of('\n',temp_uid);

	std::istringstream str(uid_buff.substr(temp_uid,(temp-temp_uid+1)));
	str >> temp_sscanf;
	str >> uid[0];
	str >> uid[1];
	str >> uid[2];
	str >> uid[3];
	
	return uid[0];
}

float proc_list::get_proc_mem(char name[])
{
	int name_fd;
	long mem,rss,lib;
	char proc_buff[512];
	char file_path[128];
	std::string temp_sscanf;
	
	sprintf(file_path,"/proc/%s/status",name);
	name_fd = open(file_path,O_RDONLY);
	read(name_fd,proc_buff,sizeof(proc_buff));
	close(name_fd);
	
	std::string mem_buff(proc_buff);
	unsigned int rss_a = mem_buff.find("VmRSS:",0);
	
	if(rss_a != std::string::npos){
		unsigned int rss_b = mem_buff.find_first_of('\n',rss_a);
		std::istringstream str(mem_buff.substr(rss_a,(rss_b-rss_a+1)));
		str >> temp_sscanf;
		str >> rss;
		
		return rss;
	}else
		return -1.0;
}

void proc_list::add_proc(char name[])
{
	int name_fd;
	ssize_t size;
	char proc_buff[256];
	char file_path[128];
	int pid,ppid,pgrp,session,tty_nr,tpgid,exit_signal,processor;
	unsigned int flags,rt_priority,policy;
	unsigned long minflt,cminflt,majflt,cmajflt,utime,stime,vsize,rsslim,startcode,endcode,startstack,kstkesp,kstkeip,signal;
	unsigned long blocked,sigignore,sigcatch,wchan,nswap,cnswap,guest_time;
	long cutime,cstime,priority,nice,num_threads,itrealvalue,rss,cguest_time;
	unsigned long long starttime,delayacct_blkio_ticks;
	char comm[20];
	char state;
	
	memset(proc_buff,'\0',sizeof(proc_buff));
	sprintf(file_path,"/proc/%s/stat",name);
	name_fd = open(file_path,O_RDONLY);
	read(name_fd,proc_buff,sizeof(proc_buff));
	close(name_fd);
	
	sscanf(proc_buff,"%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld",
		&pid,comm,&state,&ppid,&pgrp,&session,&tty_nr,&tpgid,&flags,&minflt,
		&cminflt,&majflt,&cmajflt,&utime,&stime,&cutime,&cstime,&priority,&nice,&num_threads,
		&itrealvalue,&starttime,&vsize,&rss,&rsslim,&startcode,&endcode,&startstack,&kstkesp,&kstkeip,
		&signal,&blocked,&sigignore,&sigcatch,&wchan,&nswap,&cnswap,&exit_signal,&processor,&rt_priority,
		&policy,&delayacct_blkio_ticks,&guest_time,&cguest_time);
	
	/*std::istringstream str(proc_buff);
	
	str >> pid;
	str >> comm;
	str >> state;
	str >> ppid;
	str >> pgrp;
	str >> session;
	str >> tty_nr;
	str >> tpgid;
	str >> flags;
	str >> minflt;
	str >> cminflt;
	str >> majflt;
	str >> cmajflt;
	str >> utime;
	str >> stime;
	str >> cutime;
	str >> cstime;
	str >> priority;
	str >> nice;
	str >> num_threads;
	str >> itrealvalue;
	str >> starttime;
	str >> vsize;
	str >> rss;
	str >> rsslim;
	str >> startcode;
	str >> endcode;
	str >> startstack;
	str >> kstkesp;
	str >> kstkeip;
	str >> signal;
	str >> blocked;
	str >> sigignore;
	str >> sigcatch;
	str >> wchan;
	str >> nswap;
	str >> cnswap;
	str >> exit_signal;
	str >> processor;
	str >> rt_priority;
	str >> policy;
	str >> delayacct_blkio_ticks;
	str >> guest_time;
	str >> cguest_time;
	*/
	struct proc_link temp_a;
	temp_a.pid = pid;
	sscanf(comm,"(%[^)]s",temp_a.comm);
	temp_a.state = state;
	temp_a.cpu_use = (utime+stime)/(get_uptime() - starttime);
	temp_a.mem_use =get_proc_mem(name);
	temp_a.uid = get_proc_uid(name);
	push_back(temp_a);
}
